Paolo Zinesi 2053062

Exercise 1

Import data

data_lakes <- read.csv("scottish_lakes_data.csv", header = TRUE, check.names = FALSE)
data_lakes

Exercise 1.1

Find min & max volume

idx_max_vol <- which.max(data_lakes[,"Volume(km3)"])
idx_min_vol <- which.min(data_lakes[,"Volume(km3)"])
lake_max_vol <- data_lakes[idx_max_vol, "Loch"]
lake_min_vol <- data_lakes[idx_min_vol, "Loch"]
max_vol <- data_lakes[idx_max_vol, "Volume(km3)"]
min_vol <- data_lakes[idx_min_vol, "Volume(km3)"]

cat("Lake with largest volume is", lake_max_vol, "with volume =", max_vol, "km^3\n")
Lake with largest volume is Loch Ness with volume = 7.45 km^3
cat("Lake with smallest volume is", lake_min_vol, "with volume =", min_vol, "km^3\n")
Lake with smallest volume is Loch Shin with volume = 0.35 km^3

Find min & max area

idx_max_area <- which.max(data_lakes[,"Area(km2)"])
idx_min_area <- which.min(data_lakes[,"Area(km2)"])
lake_max_area <- data_lakes[idx_max_area, "Loch"]
lake_min_area <- data_lakes[idx_min_area, "Loch"]
max_area <- data_lakes[idx_max_area, "Area(km2)"]
min_area <- data_lakes[idx_min_area, "Area(km2)"]


cat("Lake with largest area is", lake_max_area, "with area =", max_area, "km^2\n")
Lake with largest area is Loch Lomond with area = 71 km^2
cat("Lake with smallest area is", lake_min_area, "with area =", min_area, "km^2\n")
Lake with smallest area is Loch Katrine with area = 12.4 km^2

Exercise 1.2

Order dataframe w.r.t. area

areasorted_data_lakes <- data_lakes[order(data_lakes[,"Area(km2)"], decreasing = TRUE),]
areasorted_data_lakes
cat("Lakes with largest areas are", areasorted_data_lakes[1,"Loch"], "and", areasorted_data_lakes[2,"Loch"], ",",
    "with areas", areasorted_data_lakes[1,"Area(km2)"], "and", areasorted_data_lakes[2,"Area(km2)"], "km^2 , respectively")
Lakes with largest areas are Loch Lomond and Loch Ness , with areas 71 and 56 km^2 , respectively

Exercise 1.3

Sum up the areas occpupied by the lakes to determine the area of Scotland covered by water

sum_area <- sum(data_lakes[,"Area(km2)"])
cat("Area of Scotland covered by lakes =", sum_area, "km^2")
Area of Scotland covered by lakes = 371.7 km^2



## Exercise 2

Exercise 2.1

Import data

data_oil <- read.csv("crude-oil-prices.csv", header = TRUE, check.names = FALSE)
data_oil

years <- data_oil[,"Year"]
prices <- data_oil[,"Oil - Crude prices since 1861 (current $)"]

Exercise 2.2

Plot oil price vs years

plot(x = years, y = prices, type = 'o',
     main = "Oil price vs years", xlab = "Year", ylab = "Oil price (current $)",
     pch = 20, col = "steelblue", cex = 0.75, lwd = 1)

axis(side = 1, at=seq(1850,2000,25))

Exercise 2.3

Find maximum price in history

idx_max_oilprice <- which.max(prices)

cat("The highest price in history is", prices[idx_max_oilprice], "$, it occured in", years[idx_max_oilprice])
The highest price in history is 111.6697 $, it occured in 2012

Exercise 2.4

Plot price derivative

prices_derivative <- (prices[-1] - prices[-(length(prices))])


plot(x = years[-(length(years))], y = prices_derivative, type = 'o',
     main = "Oil price derivative vs years", xlab = "Year", ylab = "Oil price derivative (current $)",
     pch = 20, col = "steelblue", cex = 0.75, lwd = 1)

axis(side = 1, at=seq(1850,2000,25))



## Exercise 3

library(tibble)
library(readr)

Exercise 3.1

Import data in Tibble format

data_coal <- read_csv("coal-production-by-country.csv", show_col_types = FALSE)
data_coal

Exercise 3.2

Count the number of countries available in the file and produce a barplot with the number of entries for each country

unique_countries <- unique(data_coal[["Entity"]])
N_countries <- length(unique_countries)
cat("Number of countries available =", N_countries)
Number of countries available = 200
counts_countries <- aggregate(x = list("Counts" = data_coal[["Entity"]]),
                              by =list("Entity" = data_coal[["Entity"]]),
                              FUN = length)
counts_countries
barplot(counts_countries[["Counts"]], names.arg = counts_countries[["Entity"]],
        main = "Occurences for each country", xlab = "Country", ylab = "Occurrences", col = "steelblue")

Exercise 3.3

Select only the years ≥ 1970 and compute the total production for each country

data_coal_after1970 <- data_coal[data_coal[["Year"]]>=1970,]

productions_after1970 <- aggregate(x = list("Coal production (TWh)" = data_coal_after1970[["Coal production (TWh)"]]),
                                  by =list("Entity" = data_coal_after1970[["Entity"]]),
                                  FUN = sum)

colnames(productions_after1970) <- c("Entity", "Coal production (TWh)")
productions_after1970

Print the top 5 countries for production

productionsorted_after1970 <- productions_after1970[order(productions_after1970[,"Coal production (TWh)"], decreasing = TRUE),]

productionsorted_after1970[c(1:5),]

Exercise 3.4

Plot production as a function of time for each of the 5 top countries

par(mfrow=c(3, 2), mar=c(4,4,4,4))

for (i in c(1:5)) {
  ent <- productionsorted_after1970[i,"Entity"]
  mask <- (data_coal_after1970[["Entity"]] == ent)
  
  plot(x = data_coal_after1970[mask, "Year"][[1]],
       y = data_coal_after1970[mask, "Coal production (TWh)"][[1]],
       main = ent, xlab = "Year", ylab = "Coal production (TWh)",
       col = "steelblue", type = 'o', pch = 20, cex = 1.5, lwd = 1.5)
}

Exercise 3.5

Plot cumulative sum of the World’s coal production over the years

yearproduction_after1970 <- aggregate(x = list("Coal production (TWh)" = data_coal_after1970[["Coal production (TWh)"]]),
                                      by =list("Year" = data_coal_after1970[["Year"]]),
                                      FUN = sum)
colnames(yearproduction_after1970) <- c("Year", "Coal production (TWh)")

plot(x = yearproduction_after1970[["Year"]],
     y = cumsum(yearproduction_after1970[["Coal production (TWh)"]]),
     main = "Cumulative production of coal over the years",
     xlab = "Year", ylab = "Coal production (TWh)",
     col = "steelblue", type = 'o', pch = 20, cex = 1.5, lwd = 1.5)



## Exercise 4

library(dplyr)

Exercise 4.1

Import data

url <- "https://raw.githubusercontent.com/owid/covid-19-data/3192ec32ed721ff4efd9081b36c0e6d8406c1114/public/data/vaccinations/vaccinations-by-manufacturer.csv"

data_vaccine <- read_csv(url, show_col_types = FALSE)

data_vaccine

Italy

Filter data for vaccines in Italy

# vaccines in sparse order (some values are missing)
italy_vaccines <- filter(data_vaccine, data_vaccine[["location"]] == "Italy")
italy_vaccines
# useful variables
avail_vaccines <- c("Moderna", "Pfizer/BioNTech", "Johnson&Johnson", "Oxford/AstraZeneca", "Novavax")

datemin <- min(italy_vaccines[["date"]])
datemax <- max(italy_vaccines[["date"]])
dates <- seq(from=datemin, to=datemax, by="days")

vaccmin <- min(italy_vaccines[["total_vaccinations"]])
vaccmax <- max(italy_vaccines[["total_vaccinations"]])

Rearrange vaccination data in order to fill al the missing values

# full tibble with 0s
df_tmp <- tibble("location"="Italy",
                 "date"=rep(dates, each=length(avail_vaccines)),
                 "vaccine"=rep(avail_vaccines, length(dates)),
                 "total_vaccinations"=0)


# combine original data with 0s and aggregate to remove duplicates
total_italy_vaccines <- tibble(aggregate(total_vaccinations ~ vaccine + date,
                                         data = rbind(df_tmp, italy_vaccines),
                                         FUN = sum))


# loop over data to set 'total_vaccinations' as the previous day if the actual one is zero
for (i in c((length(avail_vaccines)+1):dim(total_italy_vaccines)[1])){
  
  if(total_italy_vaccines[i,"total_vaccinations"] == 0){
    total_italy_vaccines[i,"total_vaccinations"] <- total_italy_vaccines[i-length(avail_vaccines),"total_vaccinations"]
  }
  
}

total_italy_vaccines

Exercise 4.2 (Italy)

Plot number of vaccines as a function of time for different manufacturers (in Italy)


# plot loop
for (i in c(1:length(avail_vaccines))) {
  vacc <- avail_vaccines[i]
  mask <- (total_italy_vaccines[["vaccine"]] == vacc)
  
  plot(x = total_italy_vaccines[mask, "date"][[1]],
       y = total_italy_vaccines[mask, "total_vaccinations"][[1]],
       xlim = c(datemin, datemax), ylim = c(vaccmin, vaccmax),
       main = "Vaccine somministrations as a function of time (Italy)",
       xlab = "Date", ylab = "Total vaccinations",
       type = 'p', pch = 20, cex = 0.5, col = i,
       axes = FALSE)
  
  par(new=TRUE)
  
}

# define axis
axis.Date(side=1, at=seq(from=datemin, to=datemax, by="months"), format="%Y-%m")
axis(side=2)

# define legend
legend(x = "topleft", legend = avail_vaccines,
       col = c(1:length(avail_vaccines)), lwd = 3)

Exercise 4.3 (Italy)

Plot total number of vaccines shot per day in Italy

dailysum_italy_vaccines <- tibble(aggregate(x = list("total_vaccinations" = total_italy_vaccines[["total_vaccinations"]]),
                                            by = list("date" = total_italy_vaccines[["date"]]),
                                            FUN = sum))
dailysum_italy_vaccines
# compute day-by-day difference
derivative_italy_vaccines <- tibble("date" = dailysum_italy_vaccines[-1, "date"][[1]],
                                    "daily_vaccinations" = (dailysum_italy_vaccines[-1, "total_vaccinations"][[1]] - dailysum_italy_vaccines[-(dim(dailysum_italy_vaccines)[1]),"total_vaccinations"][[1]]))

derivative_italy_vaccines
NA
plot(x = derivative_italy_vaccines[["date"]],
     y = derivative_italy_vaccines[["daily_vaccinations"]],
     type = 'o', main = "Daily vaccinations as a function of time (in Italy)",
     xlab = "Date", ylab = "Vaccinations per day",
     pch = 20, col = "steelblue", cex = 0.75, lwd = 1,
     axes = FALSE)

# define axis
axis.Date(side=1, at=dates[c(TRUE, rep(FALSE,20))], format="%Y-%m-%d")
axis(side=2)

Let’s repeat the same plots for Germany and United States of America:

Germany

Filter data for vaccines in Germany

# vaccines in sparse order (some values are missing)
germany_vaccines <- filter(data_vaccine, data_vaccine[["location"]] == "Germany")
germany_vaccines
# useful variables
avail_vaccines <- c("Moderna", "Pfizer/BioNTech", "Johnson&Johnson", "Oxford/AstraZeneca", "Novavax")

datemin <- min(germany_vaccines[["date"]])
datemax <- max(germany_vaccines[["date"]])
dates <- seq(from=datemin, to=datemax, by="days")

vaccmin <- min(germany_vaccines[["total_vaccinations"]])
vaccmax <- max(germany_vaccines[["total_vaccinations"]])

Rearrange vaccination data in order to fill al the missing values

# full tibble with 0s
df_tmp <- tibble("location"="Germany",
                 "date"=rep(dates, each=length(avail_vaccines)),
                 "vaccine"=rep(avail_vaccines, length(dates)),
                 "total_vaccinations"=0)


# combine original data with 0s and aggregate to remove duplicates
total_germany_vaccines <- tibble(aggregate(total_vaccinations ~ vaccine + date,
                                         data = rbind(df_tmp, germany_vaccines),
                                         FUN = sum))


# loop over data to set 'total_vaccinations' as the previous day if the actual one is zero
for (i in c((length(avail_vaccines)+1):dim(total_germany_vaccines)[1])){
  
  if(total_germany_vaccines[i,"total_vaccinations"] == 0){
    total_germany_vaccines[i,"total_vaccinations"] <- total_germany_vaccines[i-length(avail_vaccines),"total_vaccinations"]
  }
  
}

total_germany_vaccines

Exercise 4.2 (Germany)

Plot number of vaccines as a function of time for different manufacturers (in Germany)


# plot loop
for (i in c(1:length(avail_vaccines))) {
  vacc <- avail_vaccines[i]
  mask <- (total_germany_vaccines[["vaccine"]] == vacc)
  
  plot(x = total_germany_vaccines[mask, "date"][[1]],
       y = total_germany_vaccines[mask, "total_vaccinations"][[1]],
       xlim = c(datemin, datemax), ylim = c(vaccmin, vaccmax),
       main = "Vaccine somministrations as a function of time (Germany)",
       xlab = "Date", ylab = "Total vaccinations",
       type = 'p', pch = 20, cex = 0.5, col = i,
       axes = FALSE)
  
  par(new=TRUE)
  
}

# define axis
axis.Date(side=1, at=seq(from=datemin, to=datemax, by="months"), format="%Y-%m")
axis(side=2)

# define legend
legend(x = "topleft", legend = avail_vaccines,
       col = c(1:length(avail_vaccines)), lwd = 3)

Exercise 4.3 (Germany)

Plot total number of vaccines shot per day in Germany

dailysum_germany_vaccines <- tibble(aggregate(x = list("total_vaccinations" = total_germany_vaccines[["total_vaccinations"]]),
                                            by = list("date" = total_germany_vaccines[["date"]]),
                                            FUN = sum))
dailysum_germany_vaccines
# compute day-by-day difference
derivative_germany_vaccines <- tibble("date" = dailysum_germany_vaccines[-1, "date"][[1]],
                                    "daily_vaccinations" = (dailysum_germany_vaccines[-1, "total_vaccinations"][[1]] - dailysum_germany_vaccines[-(dim(dailysum_germany_vaccines)[1]),"total_vaccinations"][[1]]))

derivative_germany_vaccines
NA
plot(x = derivative_germany_vaccines[["date"]],
     y = derivative_germany_vaccines[["daily_vaccinations"]],
     type = 'o', main = "Daily vaccinations as a function of time (in Germany)",
     xlab = "Date", ylab = "Vaccinations per day",
     pch = 20, col = "steelblue", cex = 0.75, lwd = 1,
     axes = FALSE)

# define axis
axis.Date(side=1, at=dates[c(TRUE, rep(FALSE,20))], format="%Y-%m-%d")
axis(side=2)

United States

Filter data for vaccines in the USA

# vaccines in sparse order (some values are missing)
usa_vaccines <- filter(data_vaccine, data_vaccine[["location"]] == "United States")
usa_vaccines

The data contain many mistakes, here we try to fix the most relevant ones…

# FIX BY HAND the biggest mistake in the original data

mask <- (usa_vaccines[["date"]] == '2022-03-16' & usa_vaccines[["vaccine"]] == 'Johnson&Johnson')
usa_vaccines[mask, "total_vaccinations"] <- 0
# useful variables
avail_vaccines <- c("Moderna", "Pfizer/BioNTech", "Johnson&Johnson")

datemin <- min(usa_vaccines[["date"]])
datemax <- max(usa_vaccines[["date"]])
dates <- seq(from=datemin, to=datemax, by="days")

vaccmin <- min(usa_vaccines[["total_vaccinations"]])
vaccmax <- max(usa_vaccines[["total_vaccinations"]])

Rearrange vaccination data in order to fill al the missing values

# complete tibble with 0s
df_tmp <- tibble("location"="United States",
                 "date"=rep(dates, each=length(avail_vaccines)),
                 "vaccine"=rep(avail_vaccines, length(dates)),
                 "total_vaccinations"=0)


# combine original data with 0s and aggregate to remove duplicates
total_usa_vaccines <- tibble(aggregate(total_vaccinations ~ vaccine + date,
                                         data = rbind(df_tmp, usa_vaccines),
                                         FUN = sum))


# loop over data to set 'total_vaccinations' as the previous day if the actual one is zero
for (i in c((length(avail_vaccines)+1):dim(total_usa_vaccines)[1])){
  
  if(total_usa_vaccines[i,"total_vaccinations"] == 0){
    total_usa_vaccines[i,"total_vaccinations"] <- total_usa_vaccines[i-length(avail_vaccines),"total_vaccinations"]
  }
  
}


total_usa_vaccines

Exercise 4.2 (United States)

Plot number of vaccines as a function of time for different manufacturers (in the United States)


# plot loop
for (i in c(1:length(avail_vaccines))) {
  vacc <- avail_vaccines[i]
  mask <- (total_usa_vaccines[["vaccine"]] == vacc)
  
  plot(x = total_usa_vaccines[mask, "date"][[1]],
       y = total_usa_vaccines[mask, "total_vaccinations"][[1]],
       xlim = c(datemin, datemax), ylim = c(vaccmin, vaccmax),
       main = "Vaccine somministrations as a function of time (United States)",
       xlab = "Date", ylab = "Total vaccinations",
       type = 'p', pch = 20, cex = 0.5, col = i,
       axes = FALSE)
  
  par(new=TRUE)
  
}

# define axis
axis.Date(side=1, at=seq(from=datemin, to=datemax, by="months"), format="%Y-%m")
axis(side=2)

# define legend
legend(x = "topleft", legend = avail_vaccines,
       col = c(1:length(avail_vaccines)), lwd = 3)

Exercise 4.3 (United States)

Plot total number of vaccines shot per day in United States

dailysum_usa_vaccines <- tibble(aggregate(x = list("total_vaccinations" = total_usa_vaccines[["total_vaccinations"]]),
                                          by = list("date" = total_usa_vaccines[["date"]]),
                                          FUN = sum))
dailysum_usa_vaccines
# compute day-by-day difference
derivative_usa_vaccines <- tibble("date" = dailysum_usa_vaccines[-1, "date"][[1]],
                                    "daily_vaccinations" = (dailysum_usa_vaccines[-1, "total_vaccinations"][[1]] - dailysum_usa_vaccines[-(dim(dailysum_usa_vaccines)[1]),"total_vaccinations"][[1]]))

derivative_usa_vaccines
NA
plot(x = derivative_usa_vaccines[["date"]],
     y = derivative_usa_vaccines[["daily_vaccinations"]],
     type = 'o', main = "Daily vaccinations as a function of time (in the United States)",
     xlab = "Date", ylab = "Vaccinations per day",
     pch = 20, col = "steelblue", cex = 0.75, lwd = 1,
     axes = FALSE)

# define axis
axis.Date(side=1, at=dates[c(TRUE, rep(FALSE,20))], format="%Y-%m-%d")
axis(side=2)

Exercise 4.4

Country-by-country data on global COVID-19 vaccinations

url <- "https://raw.githubusercontent.com/owid/covid-19-data/master/public/data/vaccinations/vaccinations.csv"

data_vaccine_countries <- read_csv(url, show_col_types = FALSE)

data_vaccine_countries

Filter data for vaccines in Europe

europe_vaccines <- filter(data_vaccine_countries, data_vaccine_countries[["iso_code"]] == "OWID_EUR")
europe_vaccines

Plot the number of daily vaccinations per million as a function of date

datemin <- min(europe_vaccines[["date"]])
datemax <- max(europe_vaccines[["date"]])
dates <- seq(from=datemin, to=datemax, by="days")


plot(x = europe_vaccines[["date"]],
     y = europe_vaccines[["daily_vaccinations_per_million"]],
     type = 'o', main = "Daily vaccinations as a function of time (in Europe)",
     xlab = "Date", ylab = "Vaccinations per million people per day",
     pch = 20, col = "steelblue", cex = 0.75, lwd = 1,
     axes = FALSE)

# define axis
axis.Date(side=1, at=dates[c(TRUE, rep(FALSE,30))], format="%Y-%m-%d")
axis(side=2)

Exercise 4.5

Produce cool plots

# select all european countries
url <- "https://raw.githubusercontent.com/ajturner/acetate/master/places/Countries-Europe.csv"
european_countries <- read_csv(url, show_col_types = FALSE)
european_countries <- european_countries[, c("name", "ISO alpha 3")]
colnames(european_countries) <- c("Country", "ISO_code")

european_countries

european_countries_vaccinations <- filter(data_vaccine_countries,
                                          ifelse(data_vaccine_countries[["iso_code"]] %in% european_countries[["ISO_code"]], TRUE, FALSE))


european_countries_vaccinations[european_countries_vaccinations[["date"]] %in% seq(from=as.Date("2022-03-20"),to=as.Date("2022-03-28"), by="days"),]
NA

Here we plot the comparison between single european countries and the average of all of them

# useful parameters
datemin <- min(european_countries_vaccinations[["date"]])
datemax <- max(european_countries_vaccinations[["date"]])
dates <- seq(from=datemin, to=datemax, by="days")
vaccmin <- min(european_countries_vaccinations[["daily_vaccinations_per_million"]], na.rm = TRUE)
vaccmax <- max(european_countries_vaccinations[["daily_vaccinations_per_million"]], na.rm = TRUE)

# plot vaccinations of all countries in Europe
plot(x = european_countries_vaccinations[["date"]],
     y = european_countries_vaccinations[["daily_vaccinations_per_million"]],
     xlim = c(datemin, datemax), ylim = c(vaccmin, vaccmax),
     xlab = "Date", ylab = "Vaccinations per million people per day",
     type = 'o', main = "Daily vaccinations as a function of time (single european countries vs european average)",
     pch = 20, cex = 0.75, lwd = 1,
     axes = FALSE)

par(new=TRUE)

# plot (mean) vaccinations of Europe
plot(x = europe_vaccines[["date"]],
     y = europe_vaccines[["daily_vaccinations_per_million"]],
     xlim = c(datemin, datemax), ylim = c(vaccmin, vaccmax),
     xlab = "", ylab = "",
     type = 'o',
     pch = 20, col = "red", cex = 0.75, lwd = 1,
     axes = FALSE)

# define axis
axis.Date(side=1, at=dates[c(TRUE, rep(FALSE,30))], format="%Y-%m-%d")
axis(side=2)

# define legend
legend(x = "topright", legend = c("European countries","Europe (average)"),
       col = c(1,2), lwd = 3)

Plot time progression of number of vaccinated people for each vaccination level

# useful parameters
datemin <- min(europe_vaccines[["date"]])
datemax <- max(europe_vaccines[["date"]])
dates <- seq(from=datemin, to=datemax, by="days")
vaccmin <- min(europe_vaccines[["people_vaccinated"]], na.rm = TRUE)
vaccmax <- max(europe_vaccines[["people_vaccinated"]], na.rm = TRUE)

avail_feat <- c("people_vaccinated", "people_fully_vaccinated", "total_boosters")

# plot loop
for (i in c(1:length(avail_feat))) {
  feat <- avail_feat[i]
  
  plot(x = europe_vaccines[, "date"][[1]],
       y = europe_vaccines[, feat][[1]],
       xlim = c(datemin, datemax), ylim = c(vaccmin, vaccmax),
       main = "Vaccinated people for each vaccination level (in Europe)",
       xlab = "Date", ylab = "Vaccinations",
       type = 'p', pch = 20, cex = 0.5, col = i+1,
       axes = FALSE)
  
  par(new=TRUE)
  
}

# define axis
axis.Date(side=1, at=dates[c(TRUE, rep(FALSE,30))], format="%Y-%m-%d")
axis(side=2)

# define legend
legend(x = "topleft", legend = c("Vaccinated", "Fully vaccinated", "Booster-vaccinated"),
       col = c(2:(length(avail_feat)+1)), lwd = 3)

Here we plot the difference between 1st-2nd dose and 2nd-booster dose number of vaccinations

par(mar=c(5, 4, 4, 4))

# correlation between first-second dose and second-booster dose choices
european_countries_actualvaccinations <- tibble(aggregate(cbind(people_vaccinated, people_fully_vaccinated, total_boosters) ~ iso_code,
                                         data = european_countries_vaccinations,
                                         FUN = max))

# useful variables
xmax <- max(european_countries_actualvaccinations[, avail_feat[2]][[1]])
ymax <- max(european_countries_actualvaccinations[, avail_feat[1]][[1]],
            european_countries_actualvaccinations[, avail_feat[3]][[1]])


# fist-vs-second dose
plot(x = european_countries_actualvaccinations[, avail_feat[2]][[1]],
     y = european_countries_actualvaccinations[, avail_feat[1]][[1]],
     xlim = c(0, xmax), ylim = c(0, ymax),
     xlab = "Fully vaccinated", ylab = "",
     main = "Comparison of 1st-2nd and 2nd-booster vaccinations",
     type = 'p', pch = 20, cex = 1, lwd = 1,
     col = "steelblue",
     axes = FALSE)

par(new=TRUE)

# second-vs-booster dose
plot(x = european_countries_actualvaccinations[, avail_feat[2]][[1]],
     y = european_countries_actualvaccinations[, avail_feat[3]][[1]],
     xlim = c(0, xmax), ylim = c(0, ymax),
     xlab = "Fully vaccinated", ylab = "",
     type = 'p', pch = 20, cex = 1, lwd = 1,
     col = "firebrick",
     axes = FALSE)

# define axis and axis labels
axis(1)
axis(2, col.axis="steelblue")
axis(4, col.axis="firebrick")
mtext("Vaccinated", side=2, line=3, cex.lab=1,las=0, col="steelblue")
mtext("Booster-vaccinated", side=4, line=3, cex.lab=1,las=0, col="firebrick")

LS0tCnRpdGxlOiAiTGFib3JhdG9yeSBTZXNzaW9uIC0gTWFyY2ggMjQsIDIwMjIiCm91dHB1dDogaHRtbF9ub3RlYm9vawplZGl0b3Jfb3B0aW9uczogCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQotLS0KCiMgUGFvbG8gWmluZXNpIDIwNTMwNjIKCiMjIEV4ZXJjaXNlIDEKCkltcG9ydCBkYXRhCgpgYGB7cn0KZGF0YV9sYWtlcyA8LSByZWFkLmNzdigic2NvdHRpc2hfbGFrZXNfZGF0YS5jc3YiLCBoZWFkZXIgPSBUUlVFLCBjaGVjay5uYW1lcyA9IEZBTFNFKQpkYXRhX2xha2VzCmBgYAoKIyMjIEV4ZXJjaXNlIDEuMQoKRmluZCBtaW4gJiBtYXggdm9sdW1lCgpgYGB7cn0KaWR4X21heF92b2wgPC0gd2hpY2gubWF4KGRhdGFfbGFrZXNbLCJWb2x1bWUoa20zKSJdKQppZHhfbWluX3ZvbCA8LSB3aGljaC5taW4oZGF0YV9sYWtlc1ssIlZvbHVtZShrbTMpIl0pCmxha2VfbWF4X3ZvbCA8LSBkYXRhX2xha2VzW2lkeF9tYXhfdm9sLCAiTG9jaCJdCmxha2VfbWluX3ZvbCA8LSBkYXRhX2xha2VzW2lkeF9taW5fdm9sLCAiTG9jaCJdCm1heF92b2wgPC0gZGF0YV9sYWtlc1tpZHhfbWF4X3ZvbCwgIlZvbHVtZShrbTMpIl0KbWluX3ZvbCA8LSBkYXRhX2xha2VzW2lkeF9taW5fdm9sLCAiVm9sdW1lKGttMykiXQoKY2F0KCJMYWtlIHdpdGggbGFyZ2VzdCB2b2x1bWUgaXMiLCBsYWtlX21heF92b2wsICJ3aXRoIHZvbHVtZSA9IiwgbWF4X3ZvbCwgImttXjNcbiIpCmNhdCgiTGFrZSB3aXRoIHNtYWxsZXN0IHZvbHVtZSBpcyIsIGxha2VfbWluX3ZvbCwgIndpdGggdm9sdW1lID0iLCBtaW5fdm9sLCAia21eM1xuIikKYGBgCgpGaW5kIG1pbiAmIG1heCBhcmVhCgpgYGB7cn0KaWR4X21heF9hcmVhIDwtIHdoaWNoLm1heChkYXRhX2xha2VzWywiQXJlYShrbTIpIl0pCmlkeF9taW5fYXJlYSA8LSB3aGljaC5taW4oZGF0YV9sYWtlc1ssIkFyZWEoa20yKSJdKQpsYWtlX21heF9hcmVhIDwtIGRhdGFfbGFrZXNbaWR4X21heF9hcmVhLCAiTG9jaCJdCmxha2VfbWluX2FyZWEgPC0gZGF0YV9sYWtlc1tpZHhfbWluX2FyZWEsICJMb2NoIl0KbWF4X2FyZWEgPC0gZGF0YV9sYWtlc1tpZHhfbWF4X2FyZWEsICJBcmVhKGttMikiXQptaW5fYXJlYSA8LSBkYXRhX2xha2VzW2lkeF9taW5fYXJlYSwgIkFyZWEoa20yKSJdCgoKY2F0KCJMYWtlIHdpdGggbGFyZ2VzdCBhcmVhIGlzIiwgbGFrZV9tYXhfYXJlYSwgIndpdGggYXJlYSA9IiwgbWF4X2FyZWEsICJrbV4yXG4iKQpjYXQoIkxha2Ugd2l0aCBzbWFsbGVzdCBhcmVhIGlzIiwgbGFrZV9taW5fYXJlYSwgIndpdGggYXJlYSA9IiwgbWluX2FyZWEsICJrbV4yXG4iKQpgYGAKCiMjIyBFeGVyY2lzZSAxLjIKCk9yZGVyIGRhdGFmcmFtZSB3LnIudC4gYXJlYQoKYGBge3J9CmFyZWFzb3J0ZWRfZGF0YV9sYWtlcyA8LSBkYXRhX2xha2VzW29yZGVyKGRhdGFfbGFrZXNbLCJBcmVhKGttMikiXSwgZGVjcmVhc2luZyA9IFRSVUUpLF0KYXJlYXNvcnRlZF9kYXRhX2xha2VzCmBgYAoKYGBge3J9CmNhdCgiTGFrZXMgd2l0aCBsYXJnZXN0IGFyZWFzIGFyZSIsIGFyZWFzb3J0ZWRfZGF0YV9sYWtlc1sxLCJMb2NoIl0sICJhbmQiLCBhcmVhc29ydGVkX2RhdGFfbGFrZXNbMiwiTG9jaCJdLCAiLCIsCiAgICAid2l0aCBhcmVhcyIsIGFyZWFzb3J0ZWRfZGF0YV9sYWtlc1sxLCJBcmVhKGttMikiXSwgImFuZCIsIGFyZWFzb3J0ZWRfZGF0YV9sYWtlc1syLCJBcmVhKGttMikiXSwgImttXjIgLCByZXNwZWN0aXZlbHkiKQpgYGAKCiMjIyBFeGVyY2lzZSAxLjMKClN1bSB1cCB0aGUgYXJlYXMgb2NjcHVwaWVkIGJ5IHRoZSBsYWtlcyB0byBkZXRlcm1pbmUgdGhlIGFyZWEgb2YgU2NvdGxhbmQgY292ZXJlZCBieSB3YXRlcgoKYGBge3J9CnN1bV9hcmVhIDwtIHN1bShkYXRhX2xha2VzWywiQXJlYShrbTIpIl0pCmNhdCgiQXJlYSBvZiBTY290bGFuZCBjb3ZlcmVkIGJ5IGxha2VzID0iLCBzdW1fYXJlYSwgImttXjIiKQpgYGAKCjxicj48YnI+CiMjIEV4ZXJjaXNlIDIKCiMjIyBFeGVyY2lzZSAyLjEKCkltcG9ydCBkYXRhCgpgYGB7cn0KZGF0YV9vaWwgPC0gcmVhZC5jc3YoImNydWRlLW9pbC1wcmljZXMuY3N2IiwgaGVhZGVyID0gVFJVRSwgY2hlY2submFtZXMgPSBGQUxTRSkKZGF0YV9vaWwKCnllYXJzIDwtIGRhdGFfb2lsWywiWWVhciJdCnByaWNlcyA8LSBkYXRhX29pbFssIk9pbCAtIENydWRlIHByaWNlcyBzaW5jZSAxODYxIChjdXJyZW50ICQpIl0KYGBgCgojIyMgRXhlcmNpc2UgMi4yCgpQbG90IG9pbCBwcmljZSB2cyB5ZWFycwoKYGBge3J9CnBsb3QoeCA9IHllYXJzLCB5ID0gcHJpY2VzLCB0eXBlID0gJ28nLAogICAgIG1haW4gPSAiT2lsIHByaWNlIHZzIHllYXJzIiwgeGxhYiA9ICJZZWFyIiwgeWxhYiA9ICJPaWwgcHJpY2UgKGN1cnJlbnQgJCkiLAogICAgIHBjaCA9IDIwLCBjb2wgPSAic3RlZWxibHVlIiwgY2V4ID0gMC43NSwgbHdkID0gMSkKCmF4aXMoc2lkZSA9IDEsIGF0PXNlcSgxODUwLDIwMDAsMjUpKQpgYGAKCiMjIyBFeGVyY2lzZSAyLjMKCkZpbmQgbWF4aW11bSBwcmljZSBpbiBoaXN0b3J5CgpgYGB7cn0KaWR4X21heF9vaWxwcmljZSA8LSB3aGljaC5tYXgocHJpY2VzKQoKY2F0KCJUaGUgaGlnaGVzdCBwcmljZSBpbiBoaXN0b3J5IGlzIiwgcHJpY2VzW2lkeF9tYXhfb2lscHJpY2VdLCAiJCwgaXQgb2NjdXJlZCBpbiIsIHllYXJzW2lkeF9tYXhfb2lscHJpY2VdKQpgYGAKCiMjIyBFeGVyY2lzZSAyLjQKClBsb3QgcHJpY2UgZGVyaXZhdGl2ZQoKYGBge3J9CnByaWNlc19kZXJpdmF0aXZlIDwtIChwcmljZXNbLTFdIC0gcHJpY2VzWy0obGVuZ3RoKHByaWNlcykpXSkKCgpwbG90KHggPSB5ZWFyc1stKGxlbmd0aCh5ZWFycykpXSwgeSA9IHByaWNlc19kZXJpdmF0aXZlLCB0eXBlID0gJ28nLAogICAgIG1haW4gPSAiT2lsIHByaWNlIGRlcml2YXRpdmUgdnMgeWVhcnMiLCB4bGFiID0gIlllYXIiLCB5bGFiID0gIk9pbCBwcmljZSBkZXJpdmF0aXZlIChjdXJyZW50ICQpIiwKICAgICBwY2ggPSAyMCwgY29sID0gInN0ZWVsYmx1ZSIsIGNleCA9IDAuNzUsIGx3ZCA9IDEpCgpheGlzKHNpZGUgPSAxLCBhdD1zZXEoMTg1MCwyMDAwLDI1KSkKCmBgYAoKPGJyPjxicj4KIyMgRXhlcmNpc2UgMwoKYGBge3J9CmxpYnJhcnkodGliYmxlKQpsaWJyYXJ5KHJlYWRyKQpgYGAKCiMjIyBFeGVyY2lzZSAzLjEKCkltcG9ydCBkYXRhIGluIFRpYmJsZSBmb3JtYXQKCmBgYHtyfQpkYXRhX2NvYWwgPC0gcmVhZF9jc3YoImNvYWwtcHJvZHVjdGlvbi1ieS1jb3VudHJ5LmNzdiIsIHNob3dfY29sX3R5cGVzID0gRkFMU0UpCmRhdGFfY29hbApgYGAKCiMjIyBFeGVyY2lzZSAzLjIKCkNvdW50IHRoZSBudW1iZXIgb2YgY291bnRyaWVzIGF2YWlsYWJsZSBpbiB0aGUgZmlsZSBhbmQgcHJvZHVjZSBhIGJhcnBsb3Qgd2l0aCB0aGUgbnVtYmVyIG9mIGVudHJpZXMgZm9yIGVhY2ggY291bnRyeQoKYGBge3J9CnVuaXF1ZV9jb3VudHJpZXMgPC0gdW5pcXVlKGRhdGFfY29hbFtbIkVudGl0eSJdXSkKTl9jb3VudHJpZXMgPC0gbGVuZ3RoKHVuaXF1ZV9jb3VudHJpZXMpCmNhdCgiTnVtYmVyIG9mIGNvdW50cmllcyBhdmFpbGFibGUgPSIsIE5fY291bnRyaWVzKQpgYGAKCmBgYHtyfQpjb3VudHNfY291bnRyaWVzIDwtIGFnZ3JlZ2F0ZSh4ID0gbGlzdCgiQ291bnRzIiA9IGRhdGFfY29hbFtbIkVudGl0eSJdXSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID1saXN0KCJFbnRpdHkiID0gZGF0YV9jb2FsW1siRW50aXR5Il1dKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRlVOID0gbGVuZ3RoKQpjb3VudHNfY291bnRyaWVzCmBgYAoKYGBge3IsIGZpZy53aWR0aD01fQpiYXJwbG90KGNvdW50c19jb3VudHJpZXNbWyJDb3VudHMiXV0sIG5hbWVzLmFyZyA9IGNvdW50c19jb3VudHJpZXNbWyJFbnRpdHkiXV0sCiAgICAgICAgbWFpbiA9ICJPY2N1cmVuY2VzIGZvciBlYWNoIGNvdW50cnkiLCB4bGFiID0gIkNvdW50cnkiLCB5bGFiID0gIk9jY3VycmVuY2VzIiwgY29sID0gInN0ZWVsYmx1ZSIpCmBgYAoKIyMjIEV4ZXJjaXNlIDMuMwoKU2VsZWN0IG9ubHkgdGhlIHllYXJzIOKJpSAxOTcwIGFuZCBjb21wdXRlIHRoZSB0b3RhbCBwcm9kdWN0aW9uIGZvciBlYWNoIGNvdW50cnkKCmBgYHtyfQpkYXRhX2NvYWxfYWZ0ZXIxOTcwIDwtIGRhdGFfY29hbFtkYXRhX2NvYWxbWyJZZWFyIl1dPj0xOTcwLF0KCnByb2R1Y3Rpb25zX2FmdGVyMTk3MCA8LSBhZ2dyZWdhdGUoeCA9IGxpc3QoIkNvYWwgcHJvZHVjdGlvbiAoVFdoKSIgPSBkYXRhX2NvYWxfYWZ0ZXIxOTcwW1siQ29hbCBwcm9kdWN0aW9uIChUV2gpIl1dKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID1saXN0KCJFbnRpdHkiID0gZGF0YV9jb2FsX2FmdGVyMTk3MFtbIkVudGl0eSJdXSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGVU4gPSBzdW0pCgpjb2xuYW1lcyhwcm9kdWN0aW9uc19hZnRlcjE5NzApIDwtIGMoIkVudGl0eSIsICJDb2FsIHByb2R1Y3Rpb24gKFRXaCkiKQpwcm9kdWN0aW9uc19hZnRlcjE5NzAKYGBgCgpQcmludCB0aGUgdG9wIDUgY291bnRyaWVzIGZvciBwcm9kdWN0aW9uCgpgYGB7cn0KcHJvZHVjdGlvbnNvcnRlZF9hZnRlcjE5NzAgPC0gcHJvZHVjdGlvbnNfYWZ0ZXIxOTcwW29yZGVyKHByb2R1Y3Rpb25zX2FmdGVyMTk3MFssIkNvYWwgcHJvZHVjdGlvbiAoVFdoKSJdLCBkZWNyZWFzaW5nID0gVFJVRSksXQoKcHJvZHVjdGlvbnNvcnRlZF9hZnRlcjE5NzBbYygxOjUpLF0KYGBgCgojIyMgRXhlcmNpc2UgMy40CgpQbG90IHByb2R1Y3Rpb24gYXMgYSBmdW5jdGlvbiBvZiB0aW1lIGZvciBlYWNoIG9mIHRoZSA1IHRvcCBjb3VudHJpZXMKCmBgYHtyLCBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD01fQpwYXIobWZyb3c9YygzLCAyKSwgbWFyPWMoNCw0LDQsNCkpCgpmb3IgKGkgaW4gYygxOjUpKSB7CiAgZW50IDwtIHByb2R1Y3Rpb25zb3J0ZWRfYWZ0ZXIxOTcwW2ksIkVudGl0eSJdCiAgbWFzayA8LSAoZGF0YV9jb2FsX2FmdGVyMTk3MFtbIkVudGl0eSJdXSA9PSBlbnQpCiAgCiAgcGxvdCh4ID0gZGF0YV9jb2FsX2FmdGVyMTk3MFttYXNrLCAiWWVhciJdW1sxXV0sCiAgICAgICB5ID0gZGF0YV9jb2FsX2FmdGVyMTk3MFttYXNrLCAiQ29hbCBwcm9kdWN0aW9uIChUV2gpIl1bWzFdXSwKICAgICAgIG1haW4gPSBlbnQsIHhsYWIgPSAiWWVhciIsIHlsYWIgPSAiQ29hbCBwcm9kdWN0aW9uIChUV2gpIiwKICAgICAgIGNvbCA9ICJzdGVlbGJsdWUiLCB0eXBlID0gJ28nLCBwY2ggPSAyMCwgY2V4ID0gMS41LCBsd2QgPSAxLjUpCn0KCmBgYAoKIyMjIEV4ZXJjaXNlIDMuNQoKUGxvdCBjdW11bGF0aXZlIHN1bSBvZiB0aGUgV29ybGTigJlzIGNvYWwgcHJvZHVjdGlvbiBvdmVyIHRoZSB5ZWFycwoKYGBge3IsIGZpZy5oZWlnaHQ9M30KeWVhcnByb2R1Y3Rpb25fYWZ0ZXIxOTcwIDwtIGFnZ3JlZ2F0ZSh4ID0gbGlzdCgiQ29hbCBwcm9kdWN0aW9uIChUV2gpIiA9IGRhdGFfY29hbF9hZnRlcjE5NzBbWyJDb2FsIHByb2R1Y3Rpb24gKFRXaCkiXV0pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID1saXN0KCJZZWFyIiA9IGRhdGFfY29hbF9hZnRlcjE5NzBbWyJZZWFyIl1dKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGVU4gPSBzdW0pCmNvbG5hbWVzKHllYXJwcm9kdWN0aW9uX2FmdGVyMTk3MCkgPC0gYygiWWVhciIsICJDb2FsIHByb2R1Y3Rpb24gKFRXaCkiKQoKcGxvdCh4ID0geWVhcnByb2R1Y3Rpb25fYWZ0ZXIxOTcwW1siWWVhciJdXSwKICAgICB5ID0gY3Vtc3VtKHllYXJwcm9kdWN0aW9uX2FmdGVyMTk3MFtbIkNvYWwgcHJvZHVjdGlvbiAoVFdoKSJdXSksCiAgICAgbWFpbiA9ICJDdW11bGF0aXZlIHByb2R1Y3Rpb24gb2YgY29hbCBvdmVyIHRoZSB5ZWFycyIsCiAgICAgeGxhYiA9ICJZZWFyIiwgeWxhYiA9ICJDb2FsIHByb2R1Y3Rpb24gKFRXaCkiLAogICAgIGNvbCA9ICJzdGVlbGJsdWUiLCB0eXBlID0gJ28nLCBwY2ggPSAyMCwgY2V4ID0gMS41LCBsd2QgPSAxLjUpCmBgYAoKPGJyPjxicj4KIyMgRXhlcmNpc2UgNApgYGB7cn0KbGlicmFyeShkcGx5cikKYGBgCgojIyMgRXhlcmNpc2UgNC4xCgpJbXBvcnQgZGF0YQpgYGB7cn0KdXJsIDwtICJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vb3dpZC9jb3ZpZC0xOS1kYXRhLzMxOTJlYzMyZWQ3MjFmZjRlZmQ5MDgxYjM2YzBlNmQ4NDA2YzExMTQvcHVibGljL2RhdGEvdmFjY2luYXRpb25zL3ZhY2NpbmF0aW9ucy1ieS1tYW51ZmFjdHVyZXIuY3N2IgoKZGF0YV92YWNjaW5lIDwtIHJlYWRfY3N2KHVybCwgc2hvd19jb2xfdHlwZXMgPSBGQUxTRSkKCmRhdGFfdmFjY2luZQpgYGAKCgojIyMgSXRhbHkKCkZpbHRlciBkYXRhIGZvciB2YWNjaW5lcyBpbiBJdGFseQoKYGBge3J9CiMgdmFjY2luZXMgaW4gc3BhcnNlIG9yZGVyIChzb21lIHZhbHVlcyBhcmUgbWlzc2luZykKaXRhbHlfdmFjY2luZXMgPC0gZmlsdGVyKGRhdGFfdmFjY2luZSwgZGF0YV92YWNjaW5lW1sibG9jYXRpb24iXV0gPT0gIkl0YWx5IikKaXRhbHlfdmFjY2luZXMKYGBgCgpgYGB7cn0KIyB1c2VmdWwgdmFyaWFibGVzCmF2YWlsX3ZhY2NpbmVzIDwtIGMoIk1vZGVybmEiLCAiUGZpemVyL0Jpb05UZWNoIiwgIkpvaG5zb24mSm9obnNvbiIsICJPeGZvcmQvQXN0cmFaZW5lY2EiLCAiTm92YXZheCIpCgpkYXRlbWluIDwtIG1pbihpdGFseV92YWNjaW5lc1tbImRhdGUiXV0pCmRhdGVtYXggPC0gbWF4KGl0YWx5X3ZhY2NpbmVzW1siZGF0ZSJdXSkKZGF0ZXMgPC0gc2VxKGZyb209ZGF0ZW1pbiwgdG89ZGF0ZW1heCwgYnk9ImRheXMiKQoKdmFjY21pbiA8LSBtaW4oaXRhbHlfdmFjY2luZXNbWyJ0b3RhbF92YWNjaW5hdGlvbnMiXV0pCnZhY2NtYXggPC0gbWF4KGl0YWx5X3ZhY2NpbmVzW1sidG90YWxfdmFjY2luYXRpb25zIl1dKQpgYGAKCgpSZWFycmFuZ2UgdmFjY2luYXRpb24gZGF0YSBpbiBvcmRlciB0byBmaWxsIGFsIHRoZSBtaXNzaW5nIHZhbHVlcwoKYGBge3J9CiMgZnVsbCB0aWJibGUgd2l0aCAwcwpkZl90bXAgPC0gdGliYmxlKCJsb2NhdGlvbiI9Ikl0YWx5IiwKICAgICAgICAgICAgICAgICAiZGF0ZSI9cmVwKGRhdGVzLCBlYWNoPWxlbmd0aChhdmFpbF92YWNjaW5lcykpLAogICAgICAgICAgICAgICAgICJ2YWNjaW5lIj1yZXAoYXZhaWxfdmFjY2luZXMsIGxlbmd0aChkYXRlcykpLAogICAgICAgICAgICAgICAgICJ0b3RhbF92YWNjaW5hdGlvbnMiPTApCgoKIyBjb21iaW5lIG9yaWdpbmFsIGRhdGEgd2l0aCAwcyBhbmQgYWdncmVnYXRlIHRvIHJlbW92ZSBkdXBsaWNhdGVzCnRvdGFsX2l0YWx5X3ZhY2NpbmVzIDwtIHRpYmJsZShhZ2dyZWdhdGUodG90YWxfdmFjY2luYXRpb25zIH4gdmFjY2luZSArIGRhdGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IHJiaW5kKGRmX3RtcCwgaXRhbHlfdmFjY2luZXMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZVTiA9IHN1bSkpCgoKIyBsb29wIG92ZXIgZGF0YSB0byBzZXQgJ3RvdGFsX3ZhY2NpbmF0aW9ucycgYXMgdGhlIHByZXZpb3VzIGRheSBpZiB0aGUgYWN0dWFsIG9uZSBpcyB6ZXJvCmZvciAoaSBpbiBjKChsZW5ndGgoYXZhaWxfdmFjY2luZXMpKzEpOmRpbSh0b3RhbF9pdGFseV92YWNjaW5lcylbMV0pKXsKICAKICBpZih0b3RhbF9pdGFseV92YWNjaW5lc1tpLCJ0b3RhbF92YWNjaW5hdGlvbnMiXSA9PSAwKXsKICAgIHRvdGFsX2l0YWx5X3ZhY2NpbmVzW2ksInRvdGFsX3ZhY2NpbmF0aW9ucyJdIDwtIHRvdGFsX2l0YWx5X3ZhY2NpbmVzW2ktbGVuZ3RoKGF2YWlsX3ZhY2NpbmVzKSwidG90YWxfdmFjY2luYXRpb25zIl0KICB9CiAgCn0KCnRvdGFsX2l0YWx5X3ZhY2NpbmVzCmBgYAoKCiMjIyBFeGVyY2lzZSA0LjIgKEl0YWx5KQoKUGxvdCBudW1iZXIgb2YgdmFjY2luZXMgYXMgYSBmdW5jdGlvbiBvZiB0aW1lIGZvciBkaWZmZXJlbnQgbWFudWZhY3R1cmVycyAoaW4gSXRhbHkpCgpgYGB7ciwgZmlnLmhlaWdodD0zLjV9CgojIHBsb3QgbG9vcApmb3IgKGkgaW4gYygxOmxlbmd0aChhdmFpbF92YWNjaW5lcykpKSB7CiAgdmFjYyA8LSBhdmFpbF92YWNjaW5lc1tpXQogIG1hc2sgPC0gKHRvdGFsX2l0YWx5X3ZhY2NpbmVzW1sidmFjY2luZSJdXSA9PSB2YWNjKQogIAogIHBsb3QoeCA9IHRvdGFsX2l0YWx5X3ZhY2NpbmVzW21hc2ssICJkYXRlIl1bWzFdXSwKICAgICAgIHkgPSB0b3RhbF9pdGFseV92YWNjaW5lc1ttYXNrLCAidG90YWxfdmFjY2luYXRpb25zIl1bWzFdXSwKICAgICAgIHhsaW0gPSBjKGRhdGVtaW4sIGRhdGVtYXgpLCB5bGltID0gYyh2YWNjbWluLCB2YWNjbWF4KSwKICAgICAgIG1haW4gPSAiVmFjY2luZSBzb21taW5pc3RyYXRpb25zIGFzIGEgZnVuY3Rpb24gb2YgdGltZSAoSXRhbHkpIiwKICAgICAgIHhsYWIgPSAiRGF0ZSIsIHlsYWIgPSAiVG90YWwgdmFjY2luYXRpb25zIiwKICAgICAgIHR5cGUgPSAncCcsIHBjaCA9IDIwLCBjZXggPSAwLjUsIGNvbCA9IGksCiAgICAgICBheGVzID0gRkFMU0UpCiAgCiAgcGFyKG5ldz1UUlVFKQogIAp9CgojIGRlZmluZSBheGlzCmF4aXMuRGF0ZShzaWRlPTEsIGF0PXNlcShmcm9tPWRhdGVtaW4sIHRvPWRhdGVtYXgsIGJ5PSJtb250aHMiKSwgZm9ybWF0PSIlWS0lbSIpCmF4aXMoc2lkZT0yKQoKIyBkZWZpbmUgbGVnZW5kCmxlZ2VuZCh4ID0gInRvcGxlZnQiLCBsZWdlbmQgPSBhdmFpbF92YWNjaW5lcywKICAgICAgIGNvbCA9IGMoMTpsZW5ndGgoYXZhaWxfdmFjY2luZXMpKSwgbHdkID0gMykKYGBgCgoKIyMjIEV4ZXJjaXNlIDQuMyAoSXRhbHkpCgpQbG90IHRvdGFsIG51bWJlciBvZiB2YWNjaW5lcyBzaG90IHBlciBkYXkgaW4gSXRhbHkKCmBgYHtyfQpkYWlseXN1bV9pdGFseV92YWNjaW5lcyA8LSB0aWJibGUoYWdncmVnYXRlKHggPSBsaXN0KCJ0b3RhbF92YWNjaW5hdGlvbnMiID0gdG90YWxfaXRhbHlfdmFjY2luZXNbWyJ0b3RhbF92YWNjaW5hdGlvbnMiXV0pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gbGlzdCgiZGF0ZSIgPSB0b3RhbF9pdGFseV92YWNjaW5lc1tbImRhdGUiXV0pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZVTiA9IHN1bSkpCmRhaWx5c3VtX2l0YWx5X3ZhY2NpbmVzCmBgYAoKYGBge3J9CiMgY29tcHV0ZSBkYXktYnktZGF5IGRpZmZlcmVuY2UKZGVyaXZhdGl2ZV9pdGFseV92YWNjaW5lcyA8LSB0aWJibGUoImRhdGUiID0gZGFpbHlzdW1faXRhbHlfdmFjY2luZXNbLTEsICJkYXRlIl1bWzFdXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImRhaWx5X3ZhY2NpbmF0aW9ucyIgPSAoZGFpbHlzdW1faXRhbHlfdmFjY2luZXNbLTEsICJ0b3RhbF92YWNjaW5hdGlvbnMiXVtbMV1dIC0gZGFpbHlzdW1faXRhbHlfdmFjY2luZXNbLShkaW0oZGFpbHlzdW1faXRhbHlfdmFjY2luZXMpWzFdKSwidG90YWxfdmFjY2luYXRpb25zIl1bWzFdXSkpCgpkZXJpdmF0aXZlX2l0YWx5X3ZhY2NpbmVzCgpgYGAKCgpgYGB7ciwgZmlnLmhlaWdodD0zLjV9CnBsb3QoeCA9IGRlcml2YXRpdmVfaXRhbHlfdmFjY2luZXNbWyJkYXRlIl1dLAogICAgIHkgPSBkZXJpdmF0aXZlX2l0YWx5X3ZhY2NpbmVzW1siZGFpbHlfdmFjY2luYXRpb25zIl1dLAogICAgIHR5cGUgPSAnbycsIG1haW4gPSAiRGFpbHkgdmFjY2luYXRpb25zIGFzIGEgZnVuY3Rpb24gb2YgdGltZSAoaW4gSXRhbHkpIiwKICAgICB4bGFiID0gIkRhdGUiLCB5bGFiID0gIlZhY2NpbmF0aW9ucyBwZXIgZGF5IiwKICAgICBwY2ggPSAyMCwgY29sID0gInN0ZWVsYmx1ZSIsIGNleCA9IDAuNzUsIGx3ZCA9IDEsCiAgICAgYXhlcyA9IEZBTFNFKQoKIyBkZWZpbmUgYXhpcwpheGlzLkRhdGUoc2lkZT0xLCBhdD1kYXRlc1tjKFRSVUUsIHJlcChGQUxTRSwyMCkpXSwgZm9ybWF0PSIlWS0lbS0lZCIpCmF4aXMoc2lkZT0yKQpgYGAKCgoKTGV0J3MgcmVwZWF0IHRoZSBzYW1lIHBsb3RzIGZvciBHZXJtYW55IGFuZCBVbml0ZWQgU3RhdGVzIG9mIEFtZXJpY2E6CgojIyMgR2VybWFueQoKRmlsdGVyIGRhdGEgZm9yIHZhY2NpbmVzIGluIEdlcm1hbnkKCmBgYHtyfQojIHZhY2NpbmVzIGluIHNwYXJzZSBvcmRlciAoc29tZSB2YWx1ZXMgYXJlIG1pc3NpbmcpCmdlcm1hbnlfdmFjY2luZXMgPC0gZmlsdGVyKGRhdGFfdmFjY2luZSwgZGF0YV92YWNjaW5lW1sibG9jYXRpb24iXV0gPT0gIkdlcm1hbnkiKQpnZXJtYW55X3ZhY2NpbmVzCmBgYAoKYGBge3J9CiMgdXNlZnVsIHZhcmlhYmxlcwphdmFpbF92YWNjaW5lcyA8LSBjKCJNb2Rlcm5hIiwgIlBmaXplci9CaW9OVGVjaCIsICJKb2huc29uJkpvaG5zb24iLCAiT3hmb3JkL0FzdHJhWmVuZWNhIiwgIk5vdmF2YXgiKQoKZGF0ZW1pbiA8LSBtaW4oZ2VybWFueV92YWNjaW5lc1tbImRhdGUiXV0pCmRhdGVtYXggPC0gbWF4KGdlcm1hbnlfdmFjY2luZXNbWyJkYXRlIl1dKQpkYXRlcyA8LSBzZXEoZnJvbT1kYXRlbWluLCB0bz1kYXRlbWF4LCBieT0iZGF5cyIpCgp2YWNjbWluIDwtIG1pbihnZXJtYW55X3ZhY2NpbmVzW1sidG90YWxfdmFjY2luYXRpb25zIl1dKQp2YWNjbWF4IDwtIG1heChnZXJtYW55X3ZhY2NpbmVzW1sidG90YWxfdmFjY2luYXRpb25zIl1dKQpgYGAKCgpSZWFycmFuZ2UgdmFjY2luYXRpb24gZGF0YSBpbiBvcmRlciB0byBmaWxsIGFsIHRoZSBtaXNzaW5nIHZhbHVlcwoKYGBge3J9CiMgZnVsbCB0aWJibGUgd2l0aCAwcwpkZl90bXAgPC0gdGliYmxlKCJsb2NhdGlvbiI9Ikdlcm1hbnkiLAogICAgICAgICAgICAgICAgICJkYXRlIj1yZXAoZGF0ZXMsIGVhY2g9bGVuZ3RoKGF2YWlsX3ZhY2NpbmVzKSksCiAgICAgICAgICAgICAgICAgInZhY2NpbmUiPXJlcChhdmFpbF92YWNjaW5lcywgbGVuZ3RoKGRhdGVzKSksCiAgICAgICAgICAgICAgICAgInRvdGFsX3ZhY2NpbmF0aW9ucyI9MCkKCgojIGNvbWJpbmUgb3JpZ2luYWwgZGF0YSB3aXRoIDBzIGFuZCBhZ2dyZWdhdGUgdG8gcmVtb3ZlIGR1cGxpY2F0ZXMKdG90YWxfZ2VybWFueV92YWNjaW5lcyA8LSB0aWJibGUoYWdncmVnYXRlKHRvdGFsX3ZhY2NpbmF0aW9ucyB+IHZhY2NpbmUgKyBkYXRlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSByYmluZChkZl90bXAsIGdlcm1hbnlfdmFjY2luZXMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZVTiA9IHN1bSkpCgoKIyBsb29wIG92ZXIgZGF0YSB0byBzZXQgJ3RvdGFsX3ZhY2NpbmF0aW9ucycgYXMgdGhlIHByZXZpb3VzIGRheSBpZiB0aGUgYWN0dWFsIG9uZSBpcyB6ZXJvCmZvciAoaSBpbiBjKChsZW5ndGgoYXZhaWxfdmFjY2luZXMpKzEpOmRpbSh0b3RhbF9nZXJtYW55X3ZhY2NpbmVzKVsxXSkpewogIAogIGlmKHRvdGFsX2dlcm1hbnlfdmFjY2luZXNbaSwidG90YWxfdmFjY2luYXRpb25zIl0gPT0gMCl7CiAgICB0b3RhbF9nZXJtYW55X3ZhY2NpbmVzW2ksInRvdGFsX3ZhY2NpbmF0aW9ucyJdIDwtIHRvdGFsX2dlcm1hbnlfdmFjY2luZXNbaS1sZW5ndGgoYXZhaWxfdmFjY2luZXMpLCJ0b3RhbF92YWNjaW5hdGlvbnMiXQogIH0KICAKfQoKdG90YWxfZ2VybWFueV92YWNjaW5lcwpgYGAKCgojIyMgRXhlcmNpc2UgNC4yIChHZXJtYW55KQoKUGxvdCBudW1iZXIgb2YgdmFjY2luZXMgYXMgYSBmdW5jdGlvbiBvZiB0aW1lIGZvciBkaWZmZXJlbnQgbWFudWZhY3R1cmVycyAoaW4gR2VybWFueSkKCmBgYHtyLCBmaWcuaGVpZ2h0PTMuNX0KCiMgcGxvdCBsb29wCmZvciAoaSBpbiBjKDE6bGVuZ3RoKGF2YWlsX3ZhY2NpbmVzKSkpIHsKICB2YWNjIDwtIGF2YWlsX3ZhY2NpbmVzW2ldCiAgbWFzayA8LSAodG90YWxfZ2VybWFueV92YWNjaW5lc1tbInZhY2NpbmUiXV0gPT0gdmFjYykKICAKICBwbG90KHggPSB0b3RhbF9nZXJtYW55X3ZhY2NpbmVzW21hc2ssICJkYXRlIl1bWzFdXSwKICAgICAgIHkgPSB0b3RhbF9nZXJtYW55X3ZhY2NpbmVzW21hc2ssICJ0b3RhbF92YWNjaW5hdGlvbnMiXVtbMV1dLAogICAgICAgeGxpbSA9IGMoZGF0ZW1pbiwgZGF0ZW1heCksIHlsaW0gPSBjKHZhY2NtaW4sIHZhY2NtYXgpLAogICAgICAgbWFpbiA9ICJWYWNjaW5lIHNvbW1pbmlzdHJhdGlvbnMgYXMgYSBmdW5jdGlvbiBvZiB0aW1lIChHZXJtYW55KSIsCiAgICAgICB4bGFiID0gIkRhdGUiLCB5bGFiID0gIlRvdGFsIHZhY2NpbmF0aW9ucyIsCiAgICAgICB0eXBlID0gJ3AnLCBwY2ggPSAyMCwgY2V4ID0gMC41LCBjb2wgPSBpLAogICAgICAgYXhlcyA9IEZBTFNFKQogIAogIHBhcihuZXc9VFJVRSkKICAKfQoKIyBkZWZpbmUgYXhpcwpheGlzLkRhdGUoc2lkZT0xLCBhdD1zZXEoZnJvbT1kYXRlbWluLCB0bz1kYXRlbWF4LCBieT0ibW9udGhzIiksIGZvcm1hdD0iJVktJW0iKQpheGlzKHNpZGU9MikKCiMgZGVmaW5lIGxlZ2VuZApsZWdlbmQoeCA9ICJ0b3BsZWZ0IiwgbGVnZW5kID0gYXZhaWxfdmFjY2luZXMsCiAgICAgICBjb2wgPSBjKDE6bGVuZ3RoKGF2YWlsX3ZhY2NpbmVzKSksIGx3ZCA9IDMpCmBgYAoKCiMjIyBFeGVyY2lzZSA0LjMgKEdlcm1hbnkpCgpQbG90IHRvdGFsIG51bWJlciBvZiB2YWNjaW5lcyBzaG90IHBlciBkYXkgaW4gR2VybWFueQoKYGBge3J9CmRhaWx5c3VtX2dlcm1hbnlfdmFjY2luZXMgPC0gdGliYmxlKGFnZ3JlZ2F0ZSh4ID0gbGlzdCgidG90YWxfdmFjY2luYXRpb25zIiA9IHRvdGFsX2dlcm1hbnlfdmFjY2luZXNbWyJ0b3RhbF92YWNjaW5hdGlvbnMiXV0pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gbGlzdCgiZGF0ZSIgPSB0b3RhbF9nZXJtYW55X3ZhY2NpbmVzW1siZGF0ZSJdXSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRlVOID0gc3VtKSkKZGFpbHlzdW1fZ2VybWFueV92YWNjaW5lcwpgYGAKCmBgYHtyfQojIGNvbXB1dGUgZGF5LWJ5LWRheSBkaWZmZXJlbmNlCmRlcml2YXRpdmVfZ2VybWFueV92YWNjaW5lcyA8LSB0aWJibGUoImRhdGUiID0gZGFpbHlzdW1fZ2VybWFueV92YWNjaW5lc1stMSwgImRhdGUiXVtbMV1dLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZGFpbHlfdmFjY2luYXRpb25zIiA9IChkYWlseXN1bV9nZXJtYW55X3ZhY2NpbmVzWy0xLCAidG90YWxfdmFjY2luYXRpb25zIl1bWzFdXSAtIGRhaWx5c3VtX2dlcm1hbnlfdmFjY2luZXNbLShkaW0oZGFpbHlzdW1fZ2VybWFueV92YWNjaW5lcylbMV0pLCJ0b3RhbF92YWNjaW5hdGlvbnMiXVtbMV1dKSkKCmRlcml2YXRpdmVfZ2VybWFueV92YWNjaW5lcwoKYGBgCgoKYGBge3IsIGZpZy5oZWlnaHQ9My41fQpwbG90KHggPSBkZXJpdmF0aXZlX2dlcm1hbnlfdmFjY2luZXNbWyJkYXRlIl1dLAogICAgIHkgPSBkZXJpdmF0aXZlX2dlcm1hbnlfdmFjY2luZXNbWyJkYWlseV92YWNjaW5hdGlvbnMiXV0sCiAgICAgdHlwZSA9ICdvJywgbWFpbiA9ICJEYWlseSB2YWNjaW5hdGlvbnMgYXMgYSBmdW5jdGlvbiBvZiB0aW1lIChpbiBHZXJtYW55KSIsCiAgICAgeGxhYiA9ICJEYXRlIiwgeWxhYiA9ICJWYWNjaW5hdGlvbnMgcGVyIGRheSIsCiAgICAgcGNoID0gMjAsIGNvbCA9ICJzdGVlbGJsdWUiLCBjZXggPSAwLjc1LCBsd2QgPSAxLAogICAgIGF4ZXMgPSBGQUxTRSkKCiMgZGVmaW5lIGF4aXMKYXhpcy5EYXRlKHNpZGU9MSwgYXQ9ZGF0ZXNbYyhUUlVFLCByZXAoRkFMU0UsMjApKV0sIGZvcm1hdD0iJVktJW0tJWQiKQpheGlzKHNpZGU9MikKYGBgCgojIyMgVW5pdGVkIFN0YXRlcwoKRmlsdGVyIGRhdGEgZm9yIHZhY2NpbmVzIGluIHRoZSBVU0EKCmBgYHtyfQojIHZhY2NpbmVzIGluIHNwYXJzZSBvcmRlciAoc29tZSB2YWx1ZXMgYXJlIG1pc3NpbmcpCnVzYV92YWNjaW5lcyA8LSBmaWx0ZXIoZGF0YV92YWNjaW5lLCBkYXRhX3ZhY2NpbmVbWyJsb2NhdGlvbiJdXSA9PSAiVW5pdGVkIFN0YXRlcyIpCnVzYV92YWNjaW5lcwpgYGAKClRoZSBkYXRhIGNvbnRhaW4gbWFueSBtaXN0YWtlcywgaGVyZSB3ZSB0cnkgdG8gZml4IHRoZSBtb3N0IHJlbGV2YW50IG9uZXMuLi4KYGBge3J9CiMgRklYIEJZIEhBTkQgdGhlIGJpZ2dlc3QgbWlzdGFrZSBpbiB0aGUgb3JpZ2luYWwgZGF0YQoKbWFzayA8LSAodXNhX3ZhY2NpbmVzW1siZGF0ZSJdXSA9PSAnMjAyMi0wMy0xNicgJiB1c2FfdmFjY2luZXNbWyJ2YWNjaW5lIl1dID09ICdKb2huc29uJkpvaG5zb24nKQp1c2FfdmFjY2luZXNbbWFzaywgInRvdGFsX3ZhY2NpbmF0aW9ucyJdIDwtIDAKYGBgCgpgYGB7cn0KIyB1c2VmdWwgdmFyaWFibGVzCmF2YWlsX3ZhY2NpbmVzIDwtIGMoIk1vZGVybmEiLCAiUGZpemVyL0Jpb05UZWNoIiwgIkpvaG5zb24mSm9obnNvbiIpCgpkYXRlbWluIDwtIG1pbih1c2FfdmFjY2luZXNbWyJkYXRlIl1dKQpkYXRlbWF4IDwtIG1heCh1c2FfdmFjY2luZXNbWyJkYXRlIl1dKQpkYXRlcyA8LSBzZXEoZnJvbT1kYXRlbWluLCB0bz1kYXRlbWF4LCBieT0iZGF5cyIpCgp2YWNjbWluIDwtIG1pbih1c2FfdmFjY2luZXNbWyJ0b3RhbF92YWNjaW5hdGlvbnMiXV0pCnZhY2NtYXggPC0gbWF4KHVzYV92YWNjaW5lc1tbInRvdGFsX3ZhY2NpbmF0aW9ucyJdXSkKYGBgCgoKUmVhcnJhbmdlIHZhY2NpbmF0aW9uIGRhdGEgaW4gb3JkZXIgdG8gZmlsbCBhbCB0aGUgbWlzc2luZyB2YWx1ZXMKCmBgYHtyfQojIGNvbXBsZXRlIHRpYmJsZSB3aXRoIDBzCmRmX3RtcCA8LSB0aWJibGUoImxvY2F0aW9uIj0iVW5pdGVkIFN0YXRlcyIsCiAgICAgICAgICAgICAgICAgImRhdGUiPXJlcChkYXRlcywgZWFjaD1sZW5ndGgoYXZhaWxfdmFjY2luZXMpKSwKICAgICAgICAgICAgICAgICAidmFjY2luZSI9cmVwKGF2YWlsX3ZhY2NpbmVzLCBsZW5ndGgoZGF0ZXMpKSwKICAgICAgICAgICAgICAgICAidG90YWxfdmFjY2luYXRpb25zIj0wKQoKCiMgY29tYmluZSBvcmlnaW5hbCBkYXRhIHdpdGggMHMgYW5kIGFnZ3JlZ2F0ZSB0byByZW1vdmUgZHVwbGljYXRlcwp0b3RhbF91c2FfdmFjY2luZXMgPC0gdGliYmxlKGFnZ3JlZ2F0ZSh0b3RhbF92YWNjaW5hdGlvbnMgfiB2YWNjaW5lICsgZGF0ZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gcmJpbmQoZGZfdG1wLCB1c2FfdmFjY2luZXMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZVTiA9IHN1bSkpCgoKIyBsb29wIG92ZXIgZGF0YSB0byBzZXQgJ3RvdGFsX3ZhY2NpbmF0aW9ucycgYXMgdGhlIHByZXZpb3VzIGRheSBpZiB0aGUgYWN0dWFsIG9uZSBpcyB6ZXJvCmZvciAoaSBpbiBjKChsZW5ndGgoYXZhaWxfdmFjY2luZXMpKzEpOmRpbSh0b3RhbF91c2FfdmFjY2luZXMpWzFdKSl7CiAgCiAgaWYodG90YWxfdXNhX3ZhY2NpbmVzW2ksInRvdGFsX3ZhY2NpbmF0aW9ucyJdID09IDApewogICAgdG90YWxfdXNhX3ZhY2NpbmVzW2ksInRvdGFsX3ZhY2NpbmF0aW9ucyJdIDwtIHRvdGFsX3VzYV92YWNjaW5lc1tpLWxlbmd0aChhdmFpbF92YWNjaW5lcyksInRvdGFsX3ZhY2NpbmF0aW9ucyJdCiAgfQogIAp9CgoKdG90YWxfdXNhX3ZhY2NpbmVzCmBgYAoKCiMjIyBFeGVyY2lzZSA0LjIgKFVuaXRlZCBTdGF0ZXMpCgpQbG90IG51bWJlciBvZiB2YWNjaW5lcyBhcyBhIGZ1bmN0aW9uIG9mIHRpbWUgZm9yIGRpZmZlcmVudCBtYW51ZmFjdHVyZXJzIChpbiB0aGUgVW5pdGVkIFN0YXRlcykKCmBgYHtyLCBmaWcuaGVpZ2h0PTMuNX0KCiMgcGxvdCBsb29wCmZvciAoaSBpbiBjKDE6bGVuZ3RoKGF2YWlsX3ZhY2NpbmVzKSkpIHsKICB2YWNjIDwtIGF2YWlsX3ZhY2NpbmVzW2ldCiAgbWFzayA8LSAodG90YWxfdXNhX3ZhY2NpbmVzW1sidmFjY2luZSJdXSA9PSB2YWNjKQogIAogIHBsb3QoeCA9IHRvdGFsX3VzYV92YWNjaW5lc1ttYXNrLCAiZGF0ZSJdW1sxXV0sCiAgICAgICB5ID0gdG90YWxfdXNhX3ZhY2NpbmVzW21hc2ssICJ0b3RhbF92YWNjaW5hdGlvbnMiXVtbMV1dLAogICAgICAgeGxpbSA9IGMoZGF0ZW1pbiwgZGF0ZW1heCksIHlsaW0gPSBjKHZhY2NtaW4sIHZhY2NtYXgpLAogICAgICAgbWFpbiA9ICJWYWNjaW5lIHNvbW1pbmlzdHJhdGlvbnMgYXMgYSBmdW5jdGlvbiBvZiB0aW1lIChVbml0ZWQgU3RhdGVzKSIsCiAgICAgICB4bGFiID0gIkRhdGUiLCB5bGFiID0gIlRvdGFsIHZhY2NpbmF0aW9ucyIsCiAgICAgICB0eXBlID0gJ3AnLCBwY2ggPSAyMCwgY2V4ID0gMC41LCBjb2wgPSBpLAogICAgICAgYXhlcyA9IEZBTFNFKQogIAogIHBhcihuZXc9VFJVRSkKICAKfQoKIyBkZWZpbmUgYXhpcwpheGlzLkRhdGUoc2lkZT0xLCBhdD1zZXEoZnJvbT1kYXRlbWluLCB0bz1kYXRlbWF4LCBieT0ibW9udGhzIiksIGZvcm1hdD0iJVktJW0iKQpheGlzKHNpZGU9MikKCiMgZGVmaW5lIGxlZ2VuZApsZWdlbmQoeCA9ICJ0b3BsZWZ0IiwgbGVnZW5kID0gYXZhaWxfdmFjY2luZXMsCiAgICAgICBjb2wgPSBjKDE6bGVuZ3RoKGF2YWlsX3ZhY2NpbmVzKSksIGx3ZCA9IDMpCmBgYAoKCiMjIyBFeGVyY2lzZSA0LjMgKFVuaXRlZCBTdGF0ZXMpCgpQbG90IHRvdGFsIG51bWJlciBvZiB2YWNjaW5lcyBzaG90IHBlciBkYXkgaW4gVW5pdGVkIFN0YXRlcwoKYGBge3J9CmRhaWx5c3VtX3VzYV92YWNjaW5lcyA8LSB0aWJibGUoYWdncmVnYXRlKHggPSBsaXN0KCJ0b3RhbF92YWNjaW5hdGlvbnMiID0gdG90YWxfdXNhX3ZhY2NpbmVzW1sidG90YWxfdmFjY2luYXRpb25zIl1dKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSBsaXN0KCJkYXRlIiA9IHRvdGFsX3VzYV92YWNjaW5lc1tbImRhdGUiXV0pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGVU4gPSBzdW0pKQpkYWlseXN1bV91c2FfdmFjY2luZXMKYGBgCgpgYGB7cn0KIyBjb21wdXRlIGRheS1ieS1kYXkgZGlmZmVyZW5jZQpkZXJpdmF0aXZlX3VzYV92YWNjaW5lcyA8LSB0aWJibGUoImRhdGUiID0gZGFpbHlzdW1fdXNhX3ZhY2NpbmVzWy0xLCAiZGF0ZSJdW1sxXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJkYWlseV92YWNjaW5hdGlvbnMiID0gKGRhaWx5c3VtX3VzYV92YWNjaW5lc1stMSwgInRvdGFsX3ZhY2NpbmF0aW9ucyJdW1sxXV0gLSBkYWlseXN1bV91c2FfdmFjY2luZXNbLShkaW0oZGFpbHlzdW1fdXNhX3ZhY2NpbmVzKVsxXSksInRvdGFsX3ZhY2NpbmF0aW9ucyJdW1sxXV0pKQoKZGVyaXZhdGl2ZV91c2FfdmFjY2luZXMKCmBgYAoKCmBgYHtyLCBmaWcuaGVpZ2h0PTMuNX0KcGxvdCh4ID0gZGVyaXZhdGl2ZV91c2FfdmFjY2luZXNbWyJkYXRlIl1dLAogICAgIHkgPSBkZXJpdmF0aXZlX3VzYV92YWNjaW5lc1tbImRhaWx5X3ZhY2NpbmF0aW9ucyJdXSwKICAgICB0eXBlID0gJ28nLCBtYWluID0gIkRhaWx5IHZhY2NpbmF0aW9ucyBhcyBhIGZ1bmN0aW9uIG9mIHRpbWUgKGluIHRoZSBVbml0ZWQgU3RhdGVzKSIsCiAgICAgeGxhYiA9ICJEYXRlIiwgeWxhYiA9ICJWYWNjaW5hdGlvbnMgcGVyIGRheSIsCiAgICAgcGNoID0gMjAsIGNvbCA9ICJzdGVlbGJsdWUiLCBjZXggPSAwLjc1LCBsd2QgPSAxLAogICAgIGF4ZXMgPSBGQUxTRSkKCiMgZGVmaW5lIGF4aXMKYXhpcy5EYXRlKHNpZGU9MSwgYXQ9ZGF0ZXNbYyhUUlVFLCByZXAoRkFMU0UsMjApKV0sIGZvcm1hdD0iJVktJW0tJWQiKQpheGlzKHNpZGU9MikKYGBgCgoKIyMjIEV4ZXJjaXNlIDQuNAoKQ291bnRyeS1ieS1jb3VudHJ5IGRhdGEgb24gZ2xvYmFsIENPVklELTE5IHZhY2NpbmF0aW9ucwpgYGB7cn0KdXJsIDwtICJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vb3dpZC9jb3ZpZC0xOS1kYXRhL21hc3Rlci9wdWJsaWMvZGF0YS92YWNjaW5hdGlvbnMvdmFjY2luYXRpb25zLmNzdiIKCmRhdGFfdmFjY2luZV9jb3VudHJpZXMgPC0gcmVhZF9jc3YodXJsLCBzaG93X2NvbF90eXBlcyA9IEZBTFNFKQoKZGF0YV92YWNjaW5lX2NvdW50cmllcwpgYGAKCkZpbHRlciBkYXRhIGZvciB2YWNjaW5lcyBpbiBFdXJvcGUKYGBge3J9CmV1cm9wZV92YWNjaW5lcyA8LSBmaWx0ZXIoZGF0YV92YWNjaW5lX2NvdW50cmllcywgZGF0YV92YWNjaW5lX2NvdW50cmllc1tbImlzb19jb2RlIl1dID09ICJPV0lEX0VVUiIpCmV1cm9wZV92YWNjaW5lcwpgYGAKUGxvdCB0aGUgbnVtYmVyIG9mIGRhaWx5IHZhY2NpbmF0aW9ucyBwZXIgbWlsbGlvbiBhcyBhIGZ1bmN0aW9uIG9mIGRhdGUKYGBge3IsIGZpZy5oZWlnaHQ9My41fQpkYXRlbWluIDwtIG1pbihldXJvcGVfdmFjY2luZXNbWyJkYXRlIl1dKQpkYXRlbWF4IDwtIG1heChldXJvcGVfdmFjY2luZXNbWyJkYXRlIl1dKQpkYXRlcyA8LSBzZXEoZnJvbT1kYXRlbWluLCB0bz1kYXRlbWF4LCBieT0iZGF5cyIpCgoKcGxvdCh4ID0gZXVyb3BlX3ZhY2NpbmVzW1siZGF0ZSJdXSwKICAgICB5ID0gZXVyb3BlX3ZhY2NpbmVzW1siZGFpbHlfdmFjY2luYXRpb25zX3Blcl9taWxsaW9uIl1dLAogICAgIHR5cGUgPSAnbycsIG1haW4gPSAiRGFpbHkgdmFjY2luYXRpb25zIGFzIGEgZnVuY3Rpb24gb2YgdGltZSAoaW4gRXVyb3BlKSIsCiAgICAgeGxhYiA9ICJEYXRlIiwgeWxhYiA9ICJWYWNjaW5hdGlvbnMgcGVyIG1pbGxpb24gcGVvcGxlIHBlciBkYXkiLAogICAgIHBjaCA9IDIwLCBjb2wgPSAic3RlZWxibHVlIiwgY2V4ID0gMC43NSwgbHdkID0gMSwKICAgICBheGVzID0gRkFMU0UpCgojIGRlZmluZSBheGlzCmF4aXMuRGF0ZShzaWRlPTEsIGF0PWRhdGVzW2MoVFJVRSwgcmVwKEZBTFNFLDMwKSldLCBmb3JtYXQ9IiVZLSVtLSVkIikKYXhpcyhzaWRlPTIpCmBgYAoKCiMjIyBFeGVyY2lzZSA0LjUKClByb2R1Y2UgY29vbCBwbG90cwpgYGB7cn0KIyBzZWxlY3QgYWxsIGV1cm9wZWFuIGNvdW50cmllcwp1cmwgPC0gImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9hanR1cm5lci9hY2V0YXRlL21hc3Rlci9wbGFjZXMvQ291bnRyaWVzLUV1cm9wZS5jc3YiCmV1cm9wZWFuX2NvdW50cmllcyA8LSByZWFkX2Nzdih1cmwsIHNob3dfY29sX3R5cGVzID0gRkFMU0UpCmV1cm9wZWFuX2NvdW50cmllcyA8LSBldXJvcGVhbl9jb3VudHJpZXNbLCBjKCJuYW1lIiwgIklTTyBhbHBoYSAzIildCmNvbG5hbWVzKGV1cm9wZWFuX2NvdW50cmllcykgPC0gYygiQ291bnRyeSIsICJJU09fY29kZSIpCgpldXJvcGVhbl9jb3VudHJpZXMKYGBgCmBgYHtyfQoKZXVyb3BlYW5fY291bnRyaWVzX3ZhY2NpbmF0aW9ucyA8LSBmaWx0ZXIoZGF0YV92YWNjaW5lX2NvdW50cmllcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRhdGFfdmFjY2luZV9jb3VudHJpZXNbWyJpc29fY29kZSJdXSAlaW4lIGV1cm9wZWFuX2NvdW50cmllc1tbIklTT19jb2RlIl1dLCBUUlVFLCBGQUxTRSkpCgoKZXVyb3BlYW5fY291bnRyaWVzX3ZhY2NpbmF0aW9uc1tldXJvcGVhbl9jb3VudHJpZXNfdmFjY2luYXRpb25zW1siZGF0ZSJdXSAlaW4lIHNlcShmcm9tPWFzLkRhdGUoIjIwMjItMDMtMjAiKSx0bz1hcy5EYXRlKCIyMDIyLTAzLTI4IiksIGJ5PSJkYXlzIiksXQoKYGBgCgpIZXJlIHdlIHBsb3QgdGhlIGNvbXBhcmlzb24gYmV0d2VlbiBzaW5nbGUgZXVyb3BlYW4gY291bnRyaWVzIGFuZCB0aGUgYXZlcmFnZSBvZiBhbGwgb2YgdGhlbQpgYGB7ciwgZmlnLmhlaWdodD0zLjV9CiMgdXNlZnVsIHBhcmFtZXRlcnMKZGF0ZW1pbiA8LSBtaW4oZXVyb3BlYW5fY291bnRyaWVzX3ZhY2NpbmF0aW9uc1tbImRhdGUiXV0pCmRhdGVtYXggPC0gbWF4KGV1cm9wZWFuX2NvdW50cmllc192YWNjaW5hdGlvbnNbWyJkYXRlIl1dKQpkYXRlcyA8LSBzZXEoZnJvbT1kYXRlbWluLCB0bz1kYXRlbWF4LCBieT0iZGF5cyIpCnZhY2NtaW4gPC0gbWluKGV1cm9wZWFuX2NvdW50cmllc192YWNjaW5hdGlvbnNbWyJkYWlseV92YWNjaW5hdGlvbnNfcGVyX21pbGxpb24iXV0sIG5hLnJtID0gVFJVRSkKdmFjY21heCA8LSBtYXgoZXVyb3BlYW5fY291bnRyaWVzX3ZhY2NpbmF0aW9uc1tbImRhaWx5X3ZhY2NpbmF0aW9uc19wZXJfbWlsbGlvbiJdXSwgbmEucm0gPSBUUlVFKQoKIyBwbG90IHZhY2NpbmF0aW9ucyBvZiBhbGwgY291bnRyaWVzIGluIEV1cm9wZQpwbG90KHggPSBldXJvcGVhbl9jb3VudHJpZXNfdmFjY2luYXRpb25zW1siZGF0ZSJdXSwKICAgICB5ID0gZXVyb3BlYW5fY291bnRyaWVzX3ZhY2NpbmF0aW9uc1tbImRhaWx5X3ZhY2NpbmF0aW9uc19wZXJfbWlsbGlvbiJdXSwKICAgICB4bGltID0gYyhkYXRlbWluLCBkYXRlbWF4KSwgeWxpbSA9IGModmFjY21pbiwgdmFjY21heCksCiAgICAgeGxhYiA9ICJEYXRlIiwgeWxhYiA9ICJWYWNjaW5hdGlvbnMgcGVyIG1pbGxpb24gcGVvcGxlIHBlciBkYXkiLAogICAgIHR5cGUgPSAnbycsIG1haW4gPSAiRGFpbHkgdmFjY2luYXRpb25zIGFzIGEgZnVuY3Rpb24gb2YgdGltZSAoc2luZ2xlIGV1cm9wZWFuIGNvdW50cmllcyB2cyBldXJvcGVhbiBhdmVyYWdlKSIsCiAgICAgcGNoID0gMjAsIGNleCA9IDAuNzUsIGx3ZCA9IDEsCiAgICAgYXhlcyA9IEZBTFNFKQoKcGFyKG5ldz1UUlVFKQoKIyBwbG90IChtZWFuKSB2YWNjaW5hdGlvbnMgb2YgRXVyb3BlCnBsb3QoeCA9IGV1cm9wZV92YWNjaW5lc1tbImRhdGUiXV0sCiAgICAgeSA9IGV1cm9wZV92YWNjaW5lc1tbImRhaWx5X3ZhY2NpbmF0aW9uc19wZXJfbWlsbGlvbiJdXSwKICAgICB4bGltID0gYyhkYXRlbWluLCBkYXRlbWF4KSwgeWxpbSA9IGModmFjY21pbiwgdmFjY21heCksCiAgICAgeGxhYiA9ICIiLCB5bGFiID0gIiIsCiAgICAgdHlwZSA9ICdvJywKICAgICBwY2ggPSAyMCwgY29sID0gInJlZCIsIGNleCA9IDAuNzUsIGx3ZCA9IDEsCiAgICAgYXhlcyA9IEZBTFNFKQoKIyBkZWZpbmUgYXhpcwpheGlzLkRhdGUoc2lkZT0xLCBhdD1kYXRlc1tjKFRSVUUsIHJlcChGQUxTRSwzMCkpXSwgZm9ybWF0PSIlWS0lbS0lZCIpCmF4aXMoc2lkZT0yKQoKIyBkZWZpbmUgbGVnZW5kCmxlZ2VuZCh4ID0gInRvcHJpZ2h0IiwgbGVnZW5kID0gYygiRXVyb3BlYW4gY291bnRyaWVzIiwiRXVyb3BlIChhdmVyYWdlKSIpLAogICAgICAgY29sID0gYygxLDIpLCBsd2QgPSAzKQpgYGAKClBsb3QgdGltZSBwcm9ncmVzc2lvbiBvZiBudW1iZXIgb2YgdmFjY2luYXRlZCBwZW9wbGUgZm9yIGVhY2ggdmFjY2luYXRpb24gbGV2ZWwKYGBge3IsIGZpZy5oZWlnaHQ9My41fQojIHVzZWZ1bCBwYXJhbWV0ZXJzCmRhdGVtaW4gPC0gbWluKGV1cm9wZV92YWNjaW5lc1tbImRhdGUiXV0pCmRhdGVtYXggPC0gbWF4KGV1cm9wZV92YWNjaW5lc1tbImRhdGUiXV0pCmRhdGVzIDwtIHNlcShmcm9tPWRhdGVtaW4sIHRvPWRhdGVtYXgsIGJ5PSJkYXlzIikKdmFjY21pbiA8LSBtaW4oZXVyb3BlX3ZhY2NpbmVzW1sicGVvcGxlX3ZhY2NpbmF0ZWQiXV0sIG5hLnJtID0gVFJVRSkKdmFjY21heCA8LSBtYXgoZXVyb3BlX3ZhY2NpbmVzW1sicGVvcGxlX3ZhY2NpbmF0ZWQiXV0sIG5hLnJtID0gVFJVRSkKCmF2YWlsX2ZlYXQgPC0gYygicGVvcGxlX3ZhY2NpbmF0ZWQiLCAicGVvcGxlX2Z1bGx5X3ZhY2NpbmF0ZWQiLCAidG90YWxfYm9vc3RlcnMiKQoKIyBwbG90IGxvb3AKZm9yIChpIGluIGMoMTpsZW5ndGgoYXZhaWxfZmVhdCkpKSB7CiAgZmVhdCA8LSBhdmFpbF9mZWF0W2ldCiAgCiAgcGxvdCh4ID0gZXVyb3BlX3ZhY2NpbmVzWywgImRhdGUiXVtbMV1dLAogICAgICAgeSA9IGV1cm9wZV92YWNjaW5lc1ssIGZlYXRdW1sxXV0sCiAgICAgICB4bGltID0gYyhkYXRlbWluLCBkYXRlbWF4KSwgeWxpbSA9IGModmFjY21pbiwgdmFjY21heCksCiAgICAgICBtYWluID0gIlZhY2NpbmF0ZWQgcGVvcGxlIGZvciBlYWNoIHZhY2NpbmF0aW9uIGxldmVsIChpbiBFdXJvcGUpIiwKICAgICAgIHhsYWIgPSAiRGF0ZSIsIHlsYWIgPSAiVmFjY2luYXRpb25zIiwKICAgICAgIHR5cGUgPSAncCcsIHBjaCA9IDIwLCBjZXggPSAwLjUsIGNvbCA9IGkrMSwKICAgICAgIGF4ZXMgPSBGQUxTRSkKICAKICBwYXIobmV3PVRSVUUpCiAgCn0KCiMgZGVmaW5lIGF4aXMKYXhpcy5EYXRlKHNpZGU9MSwgYXQ9ZGF0ZXNbYyhUUlVFLCByZXAoRkFMU0UsMzApKV0sIGZvcm1hdD0iJVktJW0tJWQiKQpheGlzKHNpZGU9MikKCiMgZGVmaW5lIGxlZ2VuZApsZWdlbmQoeCA9ICJ0b3BsZWZ0IiwgbGVnZW5kID0gYygiVmFjY2luYXRlZCIsICJGdWxseSB2YWNjaW5hdGVkIiwgIkJvb3N0ZXItdmFjY2luYXRlZCIpLAogICAgICAgY29sID0gYygyOihsZW5ndGgoYXZhaWxfZmVhdCkrMSkpLCBsd2QgPSAzKQpgYGAKCgpIZXJlIHdlIHBsb3QgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiAxc3QtMm5kIGRvc2UgYW5kIDJuZC1ib29zdGVyIGRvc2UgbnVtYmVyIG9mIHZhY2NpbmF0aW9ucwpgYGB7ciwgZmlnLmhlaWdodD0zLCBmaWcud2lkdGg9M30KcGFyKG1hcj1jKDUsIDQsIDQsIDQpKQoKIyBjb3JyZWxhdGlvbiBiZXR3ZWVuIGZpcnN0LXNlY29uZCBkb3NlIGFuZCBzZWNvbmQtYm9vc3RlciBkb3NlIGNob2ljZXMKZXVyb3BlYW5fY291bnRyaWVzX2FjdHVhbHZhY2NpbmF0aW9ucyA8LSB0aWJibGUoYWdncmVnYXRlKGNiaW5kKHBlb3BsZV92YWNjaW5hdGVkLCBwZW9wbGVfZnVsbHlfdmFjY2luYXRlZCwgdG90YWxfYm9vc3RlcnMpIH4gaXNvX2NvZGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IGV1cm9wZWFuX2NvdW50cmllc192YWNjaW5hdGlvbnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRlVOID0gbWF4KSkKCiMgdXNlZnVsIHZhcmlhYmxlcwp4bWF4IDwtIG1heChldXJvcGVhbl9jb3VudHJpZXNfYWN0dWFsdmFjY2luYXRpb25zWywgYXZhaWxfZmVhdFsyXV1bWzFdXSkKeW1heCA8LSBtYXgoZXVyb3BlYW5fY291bnRyaWVzX2FjdHVhbHZhY2NpbmF0aW9uc1ssIGF2YWlsX2ZlYXRbMV1dW1sxXV0sCiAgICAgICAgICAgIGV1cm9wZWFuX2NvdW50cmllc19hY3R1YWx2YWNjaW5hdGlvbnNbLCBhdmFpbF9mZWF0WzNdXVtbMV1dKQoKCiMgZmlzdC12cy1zZWNvbmQgZG9zZQpwbG90KHggPSBldXJvcGVhbl9jb3VudHJpZXNfYWN0dWFsdmFjY2luYXRpb25zWywgYXZhaWxfZmVhdFsyXV1bWzFdXSwKICAgICB5ID0gZXVyb3BlYW5fY291bnRyaWVzX2FjdHVhbHZhY2NpbmF0aW9uc1ssIGF2YWlsX2ZlYXRbMV1dW1sxXV0sCiAgICAgeGxpbSA9IGMoMCwgeG1heCksIHlsaW0gPSBjKDAsIHltYXgpLAogICAgIHhsYWIgPSAiRnVsbHkgdmFjY2luYXRlZCIsIHlsYWIgPSAiIiwKICAgICBtYWluID0gIkNvbXBhcmlzb24gb2YgMXN0LTJuZCBhbmQgMm5kLWJvb3N0ZXIgdmFjY2luYXRpb25zIiwKICAgICB0eXBlID0gJ3AnLCBwY2ggPSAyMCwgY2V4ID0gMSwgbHdkID0gMSwKICAgICBjb2wgPSAic3RlZWxibHVlIiwKICAgICBheGVzID0gRkFMU0UpCgpwYXIobmV3PVRSVUUpCgojIHNlY29uZC12cy1ib29zdGVyIGRvc2UKcGxvdCh4ID0gZXVyb3BlYW5fY291bnRyaWVzX2FjdHVhbHZhY2NpbmF0aW9uc1ssIGF2YWlsX2ZlYXRbMl1dW1sxXV0sCiAgICAgeSA9IGV1cm9wZWFuX2NvdW50cmllc19hY3R1YWx2YWNjaW5hdGlvbnNbLCBhdmFpbF9mZWF0WzNdXVtbMV1dLAogICAgIHhsaW0gPSBjKDAsIHhtYXgpLCB5bGltID0gYygwLCB5bWF4KSwKICAgICB4bGFiID0gIkZ1bGx5IHZhY2NpbmF0ZWQiLCB5bGFiID0gIiIsCiAgICAgdHlwZSA9ICdwJywgcGNoID0gMjAsIGNleCA9IDEsIGx3ZCA9IDEsCiAgICAgY29sID0gImZpcmVicmljayIsCiAgICAgYXhlcyA9IEZBTFNFKQoKIyBkZWZpbmUgYXhpcyBhbmQgYXhpcyBsYWJlbHMKYXhpcygxKQpheGlzKDIsIGNvbC5heGlzPSJzdGVlbGJsdWUiKQpheGlzKDQsIGNvbC5heGlzPSJmaXJlYnJpY2siKQptdGV4dCgiVmFjY2luYXRlZCIsIHNpZGU9MiwgbGluZT0zLCBjZXgubGFiPTEsbGFzPTAsIGNvbD0ic3RlZWxibHVlIikKbXRleHQoIkJvb3N0ZXItdmFjY2luYXRlZCIsIHNpZGU9NCwgbGluZT0zLCBjZXgubGFiPTEsbGFzPTAsIGNvbD0iZmlyZWJyaWNrIikKYGBgCg==